Objective

The aim of this section is to present the different widgets used for the exploration of hypercubes and developped during the ODYCCEUS project. We adapt a little the initial programs for the case of octocubes that are used in IMAGEUN but the principles remains the same. Each widget will export a dataframe and a plotly figure, making possible to store the results in javascript and/or to use the table for development with another software.

Preparation

Load multilevel octocubes and transform in hypercubes

We load the octocubes at different levels of time agregation and transform them in hypercubes by removing the dual dimensions of states and regions

base<-readRDS("octocubes/hc_mycorpus_covid_states_regions.RDS")
hc_day<-base$day[,.(tag=sum(tags),news=sum(news)),.(who,what,when,states=states1,regions=regions1)]
hc_week<-base$week[,.(tag=sum(tags),news=sum(news)),.(who,what,when,states=states1,regions=regions1)]
hc_month<-base$month[,.(tag=sum(tags),news=sum(news)),.(who,what,when,states=states1,regions=regions1)]
hc_year<-base$year[,.(tag=sum(tags),news=sum(news)),.(who,what,when,states=states1,regions=regions1)]

Load statistical test function

#### ---------------- testchi2 ----------------
#' @title  Compute the average salience of the topic and test significance of deviation
#' @name what
#' @description create a table and graphic of the topic
#' @param tabtest a table with variable trial, success and null.value
#' @param minsamp : Threshold of sample size requested for salience computation
#' @param mintest : Threshold of estimated value requested for chi-square test


testchi2<-function(tabtest=tabtest,
                   minsamp = 20,
                   mintest = 5) 
{
  tab<-tabtest
  n<-dim(tab)[1]
  
  # Compute salience if sample size sufficient (default : N>20)
  tab$estimate <-NA
  tab$salience <-NA
  tab$chi2<-NA
  tab$p.value<-NA
   tab$estimate<-round(tab$success/tab$trial,5)
   tab$salience<-tab$estimate/tab$null.value
  
  # Chi-square test if estimated value sufficient (default : Nij* > 5)
  
  for (i in 1:n) {
    if(tab$trial[i]*tab$null.value[i]>=mintest) {  
      test<-prop.test(x=tab$success[i],n=tab$trial[i], p=tab$null.value[i], 
                      alternative = "greater")
      tab$chi2[i]<-round(test$statistic,2)
      tab$p.value[i]<-round(test$p.value,5)
    } 
  }
 # }
  return(tab)
}

What

Function

### ---------------- what ----------------
#' @title  Compute the average salience of the topic
#' @name what
#' @description create a table and graphic of the topic
#' @param hc an hypercube prepared as data.table
#' @param subtop a subtag of the main tag (default = NA)
#' @param title Title of the graphic


what <- function (hc = hypercube,
                  what = "what",
                  subtop = NA,
                  title = "What ?")
{
 
  
tab<-hc
tab$what<-tab[[what]]
if (is.na(subtop)){tab$what <-tab$what !="_no_"}else {tab$what <- tab$what == subtop}

tab<-tab[,list(news = sum(news)),by = what]
tab$pct<-100*tab$news/sum(tab$news)

p <- plot_ly(tab,
             labels = ~what,
             values = ~pct,
             type = 'pie') %>%
  layout(title = title,
         xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE),
         yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE))

output<-list("table" = tab, "plotly" =p)

return(output)

}

Application 1 : covid topic

res<-what(hc_year)
res$table
res$plotly

Application n°2 : state subtopic

res <-hc_year %>% filter(states != "_no_") %>%
what(what = "states",
     subtop ="RUS",
     title = "Share of Russia in state news")
res$table
res$plotly

Application n°3 : macroregion subtopic

res <-hc_year %>% filter(regions != "_no_") %>%
what(what = "regions",
     subtop ="OR_EU",
     title = "Share of EU in macroregional news")
res$table
res$plotly

Who.What

function

#### ---------------- who.what ----------------
#' @title  visualize variation of the topic between media
#' @name who.what
#' @description create a table of variation of the topic by media
#' @param hc an hypercube prepared as data.table
#' @param test : visualize test (TRUE) or salience (FALSE)
#' @param minsamp : Threshold of sample size requested for salience computation
#' @param mintest sample size of estimate for chi-square test (default = 5)
#' @param title Title of the graphic


who.what <- function (hc = hypercube,
                      what = "what",
                      subtop = NA,
                      test = FALSE,
                      minsamp = 20,
                      mintest = 5,
                      title = "Who says What ?")
{
  
  tab<-hc
  tab$what<-tab[[what]]
if (is.na(subtop)){tab$what <-tab$what !="_no_"}else {tab$what <- tab$what == subtop}
#  {tab$what <-tab$what !="_no_"}
  
  tab<-tab[,list(trial = sum(news),success=round(sum(news*what),0)),by = list(who)]
  ref <-round(sum(tab$success)/sum(tab$trial),4)
  tab$null.value<-ref
  
  tab<-testchi2(tabtest=tab,
                minsamp = minsamp,
                mintest = mintest)
  
  
  
  if (test==FALSE) {tab$index =tab$salience
  tab<-tab[tab$trial > minsamp,]
  mycol<-brewer.pal(7,"YlOrRd")
  } 
  else {tab$index=tab$p.value
  tab<-tab[tab$trial*tab$null.value>mintest,]
  mycol<-brewer.pal(7,"RdYlBu")
  mycol[4]<-"lightyellow"
  }
  
  p <- plot_ly(tab,
               x = ~who,
               y = ~estimate*100,
               color= ~index,
               colors= mycol,
               hoverinfo = "text",
               text = ~paste('Source: ',who,
                             '<br /> Total news  : ', round(trial,0),
                             '<br /> Topic news : ', round(success,0),
                             '<br /> % observed  : ', round(estimate*100,2),'%',
                             '<br /> % estimated : ', round(null.value*100,2),'%',
                             '<br /> Salience : ', round(salience,2),  
                             '<br /> p.value : ', round(p.value,4)),
               type = "bar")  %>%
    layout(title = title,
           yaxis = list(title = "% news"),
           barmode = 'stack')
  
  output<-list("table" = tab, "plotly" =p)
  
  return(output)
  
}

Applicaton n°1 : covid topic

who.what(hc_year)
$table

$plotly
Warning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arrays
NA

Application n°2 : state subtopic

res <-hc_year %>% filter(states != "_no_") %>%
who.what(what = "states",
     subtop ="RUS",
     title = "Share of Russia in international news",
     test=TRUE)
res$table
res$plotly

Application n°3 : macroregion subtopic

res <-hc_year %>% filter(regions != "_no_") %>%
who.what(what = "regions",
     subtop ="OR_EU",
     title = "Share of EU in macroregional news",
     test=TRUE)
res$table
res$plotly
Warning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arrays
LS0tCnRpdGxlOiAiR2VvZ3JhcGhpY2FsIGFuYWx5c2lzIG9mIG1lZGlhIgpzdWJ0aXRsZTogIjUuIFdpZGdldHMiCmF1dGhvcjogIkNsYXVkZSBHcmFzbGFuZCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyIHNldHVwNSwgZWNobyA9IEZBTFNFLCBjb21tZW50ID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGNvbW1lbnQgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShkcGx5cikKbGlicmFyeShrbml0cikKI2xpYnJhcnkodGlkeWdyYXBoKQojbGlicmFyeShnZ3JhcGgpCiNsaWJyYXJ5KHZpc05ldHdvcmspCmBgYAoKCgojIyBPYmplY3RpdmUKClRoZSBhaW0gb2YgdGhpcyBzZWN0aW9uIGlzIHRvIHByZXNlbnQgdGhlIGRpZmZlcmVudCB3aWRnZXRzIHVzZWQgZm9yIHRoZSBleHBsb3JhdGlvbiBvZiBoeXBlcmN1YmVzIGFuZCBkZXZlbG9wcGVkIGR1cmluZyB0aGUgT0RZQ0NFVVMgcHJvamVjdC4gV2UgYWRhcHQgYSBsaXR0bGUgdGhlIGluaXRpYWwgcHJvZ3JhbXMgZm9yIHRoZSBjYXNlIG9mIG9jdG9jdWJlcyB0aGF0IGFyZSB1c2VkIGluIElNQUdFVU4gYnV0IHRoZSBwcmluY2lwbGVzIHJlbWFpbnMgdGhlIHNhbWUuIEVhY2ggd2lkZ2V0IHdpbGwgZXhwb3J0IGEgZGF0YWZyYW1lIGFuZCBhIHBsb3RseSBmaWd1cmUsIG1ha2luZyBwb3NzaWJsZSB0byBzdG9yZSB0aGUgcmVzdWx0cyBpbiBqYXZhc2NyaXB0IGFuZC9vciB0byB1c2UgdGhlIHRhYmxlIGZvciBkZXZlbG9wbWVudCB3aXRoIGFub3RoZXIgc29mdHdhcmUuCgoKCiMjIFByZXBhcmF0aW9uCgojIyMgTG9hZCBtdWx0aWxldmVsIG9jdG9jdWJlcyBhbmQgdHJhbnNmb3JtIGluIGh5cGVyY3ViZXMKCldlIGxvYWQgdGhlIG9jdG9jdWJlcyBhdCBkaWZmZXJlbnQgbGV2ZWxzIG9mIHRpbWUgYWdyZWdhdGlvbiBhbmQgdHJhbnNmb3JtIHRoZW0gaW4gaHlwZXJjdWJlcyBieSByZW1vdmluZyB0aGUgZHVhbCBkaW1lbnNpb25zIG9mIHN0YXRlcyBhbmQgcmVnaW9ucwoKYGBge3J9CmJhc2U8LXJlYWRSRFMoIm9jdG9jdWJlcy9oY19teWNvcnB1c19jb3ZpZF9zdGF0ZXNfcmVnaW9ucy5SRFMiKQpoY19kYXk8LWJhc2UkZGF5WywuKHRhZz1zdW0odGFncyksbmV3cz1zdW0obmV3cykpLC4od2hvLHdoYXQsd2hlbixzdGF0ZXM9c3RhdGVzMSxyZWdpb25zPXJlZ2lvbnMxKV0KaGNfd2VlazwtYmFzZSR3ZWVrWywuKHRhZz1zdW0odGFncyksbmV3cz1zdW0obmV3cykpLC4od2hvLHdoYXQsd2hlbixzdGF0ZXM9c3RhdGVzMSxyZWdpb25zPXJlZ2lvbnMxKV0KaGNfbW9udGg8LWJhc2UkbW9udGhbLC4odGFnPXN1bSh0YWdzKSxuZXdzPXN1bShuZXdzKSksLih3aG8sd2hhdCx3aGVuLHN0YXRlcz1zdGF0ZXMxLHJlZ2lvbnM9cmVnaW9uczEpXQpoY195ZWFyPC1iYXNlJHllYXJbLC4odGFnPXN1bSh0YWdzKSxuZXdzPXN1bShuZXdzKSksLih3aG8sd2hhdCx3aGVuLHN0YXRlcz1zdGF0ZXMxLHJlZ2lvbnM9cmVnaW9uczEpXQpgYGAKCgojIyMgTG9hZCBzdGF0aXN0aWNhbCB0ZXN0IGZ1bmN0aW9uCgpgYGB7cn0KIyMjIyAtLS0tLS0tLS0tLS0tLS0tIHRlc3RjaGkyIC0tLS0tLS0tLS0tLS0tLS0KIycgQHRpdGxlICBDb21wdXRlIHRoZSBhdmVyYWdlIHNhbGllbmNlIG9mIHRoZSB0b3BpYyBhbmQgdGVzdCBzaWduaWZpY2FuY2Ugb2YgZGV2aWF0aW9uCiMnIEBuYW1lIHdoYXQKIycgQGRlc2NyaXB0aW9uIGNyZWF0ZSBhIHRhYmxlIGFuZCBncmFwaGljIG9mIHRoZSB0b3BpYwojJyBAcGFyYW0gdGFidGVzdCBhIHRhYmxlIHdpdGggdmFyaWFibGUgdHJpYWwsIHN1Y2Nlc3MgYW5kIG51bGwudmFsdWUKIycgQHBhcmFtIG1pbnNhbXAgOiBUaHJlc2hvbGQgb2Ygc2FtcGxlIHNpemUgcmVxdWVzdGVkIGZvciBzYWxpZW5jZSBjb21wdXRhdGlvbgojJyBAcGFyYW0gbWludGVzdCA6IFRocmVzaG9sZCBvZiBlc3RpbWF0ZWQgdmFsdWUgcmVxdWVzdGVkIGZvciBjaGktc3F1YXJlIHRlc3QKCgp0ZXN0Y2hpMjwtZnVuY3Rpb24odGFidGVzdD10YWJ0ZXN0LAogICAgICAgICAgICAgICAgICAgbWluc2FtcCA9IDIwLAogICAgICAgICAgICAgICAgICAgbWludGVzdCA9IDUpIAp7CiAgdGFiPC10YWJ0ZXN0CiAgbjwtZGltKHRhYilbMV0KICAKICAjIENvbXB1dGUgc2FsaWVuY2UgaWYgc2FtcGxlIHNpemUgc3VmZmljaWVudCAoZGVmYXVsdCA6IE4+MjApCiAgdGFiJGVzdGltYXRlIDwtTkEKICB0YWIkc2FsaWVuY2UgPC1OQQogIHRhYiRjaGkyPC1OQQogIHRhYiRwLnZhbHVlPC1OQQogICB0YWIkZXN0aW1hdGU8LXJvdW5kKHRhYiRzdWNjZXNzL3RhYiR0cmlhbCw1KQogICB0YWIkc2FsaWVuY2U8LXRhYiRlc3RpbWF0ZS90YWIkbnVsbC52YWx1ZQogIAogICMgQ2hpLXNxdWFyZSB0ZXN0IGlmIGVzdGltYXRlZCB2YWx1ZSBzdWZmaWNpZW50IChkZWZhdWx0IDogTmlqKiA+IDUpCiAgCiAgZm9yIChpIGluIDE6bikgewogICAgaWYodGFiJHRyaWFsW2ldKnRhYiRudWxsLnZhbHVlW2ldPj1taW50ZXN0KSB7ICAKICAgICAgdGVzdDwtcHJvcC50ZXN0KHg9dGFiJHN1Y2Nlc3NbaV0sbj10YWIkdHJpYWxbaV0sIHA9dGFiJG51bGwudmFsdWVbaV0sIAogICAgICAgICAgICAgICAgICAgICAgYWx0ZXJuYXRpdmUgPSAiZ3JlYXRlciIpCiAgICAgIHRhYiRjaGkyW2ldPC1yb3VuZCh0ZXN0JHN0YXRpc3RpYywyKQogICAgICB0YWIkcC52YWx1ZVtpXTwtcm91bmQodGVzdCRwLnZhbHVlLDUpCiAgICB9IAogIH0KICMgfQogIHJldHVybih0YWIpCn0KCmBgYAoKIyMgV2hhdAoKCiMjIyBGdW5jdGlvbgoKYGBge3J9CiMjIyAtLS0tLS0tLS0tLS0tLS0tIHdoYXQgLS0tLS0tLS0tLS0tLS0tLQojJyBAdGl0bGUgIENvbXB1dGUgdGhlIGF2ZXJhZ2Ugc2FsaWVuY2Ugb2YgdGhlIHRvcGljCiMnIEBuYW1lIHdoYXQKIycgQGRlc2NyaXB0aW9uIGNyZWF0ZSBhIHRhYmxlIGFuZCBncmFwaGljIG9mIHRoZSB0b3BpYwojJyBAcGFyYW0gaGMgYW4gaHlwZXJjdWJlIHByZXBhcmVkIGFzIGRhdGEudGFibGUKIycgQHBhcmFtIHN1YnRvcCBhIHN1YnRhZyBvZiB0aGUgbWFpbiB0YWcgKGRlZmF1bHQgPSBOQSkKIycgQHBhcmFtIHRpdGxlIFRpdGxlIG9mIHRoZSBncmFwaGljCgoKd2hhdCA8LSBmdW5jdGlvbiAoaGMgPSBoeXBlcmN1YmUsCiAgICAgICAgICAgICAgICAgIHdoYXQgPSAid2hhdCIsCiAgICAgICAgICAgICAgICAgIHN1YnRvcCA9IE5BLAogICAgICAgICAgICAgICAgICB0aXRsZSA9ICJXaGF0ID8iKQp7CiAKICAKdGFiPC1oYwp0YWIkd2hhdDwtdGFiW1t3aGF0XV0KaWYgKGlzLm5hKHN1YnRvcCkpe3RhYiR3aGF0IDwtdGFiJHdoYXQgIT0iX25vXyJ9ZWxzZSB7dGFiJHdoYXQgPC0gdGFiJHdoYXQgPT0gc3VidG9wfQoKdGFiPC10YWJbLGxpc3QobmV3cyA9IHN1bShuZXdzKSksYnkgPSB3aGF0XQp0YWIkcGN0PC0xMDAqdGFiJG5ld3Mvc3VtKHRhYiRuZXdzKQoKcCA8LSBwbG90X2x5KHRhYiwKICAgICAgICAgICAgIGxhYmVscyA9IH53aGF0LAogICAgICAgICAgICAgdmFsdWVzID0gfnBjdCwKICAgICAgICAgICAgIHR5cGUgPSAncGllJykgJT4lCiAgbGF5b3V0KHRpdGxlID0gdGl0bGUsCiAgICAgICAgIHhheGlzID0gbGlzdChzaG93Z3JpZCA9IEZBTFNFLCB6ZXJvbGluZSA9IEZBTFNFLCBzaG93dGlja2xhYmVscyA9IEZBTFNFKSwKICAgICAgICAgeWF4aXMgPSBsaXN0KHNob3dncmlkID0gRkFMU0UsIHplcm9saW5lID0gRkFMU0UsIHNob3d0aWNrbGFiZWxzID0gRkFMU0UpKQoKb3V0cHV0PC1saXN0KCJ0YWJsZSIgPSB0YWIsICJwbG90bHkiID1wKQoKcmV0dXJuKG91dHB1dCkKCn0KYGBgCgojIyMgQXBwbGljYXRpb24gMSA6IGNvdmlkIHRvcGljCgoKYGBge3J9CnJlczwtd2hhdChoY195ZWFyKQpyZXMkdGFibGUKcmVzJHBsb3RseQpgYGAKCgojIyMgQXBwbGljYXRpb24gbsKwMiA6IHN0YXRlIHN1YnRvcGljCgpgYGB7cn0KcmVzIDwtaGNfeWVhciAlPiUgZmlsdGVyKHN0YXRlcyAhPSAiX25vXyIpICU+JQp3aGF0KHdoYXQgPSAic3RhdGVzIiwKICAgICBzdWJ0b3AgPSJSVVMiLAogICAgIHRpdGxlID0gIlNoYXJlIG9mIFJ1c3NpYSBpbiBpbnRlcm5hdGlvbmFsIG5ld3MiKQpyZXMkdGFibGUKcmVzJHBsb3RseQpgYGAKCiMjIyBBcHBsaWNhdGlvbiBuwrAzIDogbWFjcm9yZWdpb24gc3VidG9waWMKCmBgYHtyfQpyZXMgPC1oY195ZWFyICU+JSBmaWx0ZXIocmVnaW9ucyAhPSAiX25vXyIpICU+JQp3aGF0KHdoYXQgPSAicmVnaW9ucyIsCiAgICAgc3VidG9wID0iT1JfRVUiLAogICAgIHRpdGxlID0gIlNoYXJlIG9mIEVVIGluIG1hY3JvcmVnaW9uYWwgbmV3cyIpCnJlcyR0YWJsZQpyZXMkcGxvdGx5CmBgYAoKIyMgV2hvLldoYXQKCiMjIyBmdW5jdGlvbgoKYGBge3J9CiMjIyMgLS0tLS0tLS0tLS0tLS0tLSB3aG8ud2hhdCAtLS0tLS0tLS0tLS0tLS0tCiMnIEB0aXRsZSAgdmlzdWFsaXplIHZhcmlhdGlvbiBvZiB0aGUgdG9waWMgYmV0d2VlbiBtZWRpYQojJyBAbmFtZSB3aG8ud2hhdAojJyBAZGVzY3JpcHRpb24gY3JlYXRlIGEgdGFibGUgb2YgdmFyaWF0aW9uIG9mIHRoZSB0b3BpYyBieSBtZWRpYQojJyBAcGFyYW0gaGMgYW4gaHlwZXJjdWJlIHByZXBhcmVkIGFzIGRhdGEudGFibGUKIycgQHBhcmFtIHRlc3QgOiB2aXN1YWxpemUgdGVzdCAoVFJVRSkgb3Igc2FsaWVuY2UgKEZBTFNFKQojJyBAcGFyYW0gbWluc2FtcCA6IFRocmVzaG9sZCBvZiBzYW1wbGUgc2l6ZSByZXF1ZXN0ZWQgZm9yIHNhbGllbmNlIGNvbXB1dGF0aW9uCiMnIEBwYXJhbSBtaW50ZXN0IHNhbXBsZSBzaXplIG9mIGVzdGltYXRlIGZvciBjaGktc3F1YXJlIHRlc3QgKGRlZmF1bHQgPSA1KQojJyBAcGFyYW0gdGl0bGUgVGl0bGUgb2YgdGhlIGdyYXBoaWMKCgp3aG8ud2hhdCA8LSBmdW5jdGlvbiAoaGMgPSBoeXBlcmN1YmUsCiAgICAgICAgICAgICAgICAgICAgICB3aGF0ID0gIndoYXQiLAogICAgICAgICAgICAgICAgICAgICAgc3VidG9wID0gTkEsCiAgICAgICAgICAgICAgICAgICAgICB0ZXN0ID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBtaW5zYW1wID0gMjAsCiAgICAgICAgICAgICAgICAgICAgICBtaW50ZXN0ID0gNSwKICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIldobyBzYXlzIFdoYXQgPyIpCnsKICAKICB0YWI8LWhjCiAgdGFiJHdoYXQ8LXRhYltbd2hhdF1dCmlmIChpcy5uYShzdWJ0b3ApKXt0YWIkd2hhdCA8LXRhYiR3aGF0ICE9Il9ub18ifWVsc2Uge3RhYiR3aGF0IDwtIHRhYiR3aGF0ID09IHN1YnRvcH0KIyAge3RhYiR3aGF0IDwtdGFiJHdoYXQgIT0iX25vXyJ9CiAgCiAgdGFiPC10YWJbLGxpc3QodHJpYWwgPSBzdW0obmV3cyksc3VjY2Vzcz1yb3VuZChzdW0obmV3cyp3aGF0KSwwKSksYnkgPSBsaXN0KHdobyldCiAgcmVmIDwtcm91bmQoc3VtKHRhYiRzdWNjZXNzKS9zdW0odGFiJHRyaWFsKSw0KQogIHRhYiRudWxsLnZhbHVlPC1yZWYKICAKICB0YWI8LXRlc3RjaGkyKHRhYnRlc3Q9dGFiLAogICAgICAgICAgICAgICAgbWluc2FtcCA9IG1pbnNhbXAsCiAgICAgICAgICAgICAgICBtaW50ZXN0ID0gbWludGVzdCkKICAKICAKICAKICBpZiAodGVzdD09RkFMU0UpIHt0YWIkaW5kZXggPXRhYiRzYWxpZW5jZQogIHRhYjwtdGFiW3RhYiR0cmlhbCA+IG1pbnNhbXAsXQogIG15Y29sPC1icmV3ZXIucGFsKDcsIllsT3JSZCIpCiAgfSAKICBlbHNlIHt0YWIkaW5kZXg9dGFiJHAudmFsdWUKICB0YWI8LXRhYlt0YWIkdHJpYWwqdGFiJG51bGwudmFsdWU+bWludGVzdCxdCiAgbXljb2w8LWJyZXdlci5wYWwoNywiUmRZbEJ1IikKICBteWNvbFs0XTwtImxpZ2h0eWVsbG93IgogIH0KICAKICBwIDwtIHBsb3RfbHkodGFiLAogICAgICAgICAgICAgICB4ID0gfndobywKICAgICAgICAgICAgICAgeSA9IH5lc3RpbWF0ZSoxMDAsCiAgICAgICAgICAgICAgIGNvbG9yPSB+aW5kZXgsCiAgICAgICAgICAgICAgIGNvbG9ycz0gbXljb2wsCiAgICAgICAgICAgICAgIGhvdmVyaW5mbyA9ICJ0ZXh0IiwKICAgICAgICAgICAgICAgdGV4dCA9IH5wYXN0ZSgnU291cmNlOiAnLHdobywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPGJyIC8+IFRvdGFsIG5ld3MgIDogJywgcm91bmQodHJpYWwsMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzxiciAvPiBUb3BpYyBuZXdzIDogJywgcm91bmQoc3VjY2VzcywwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPGJyIC8+ICUgb2JzZXJ2ZWQgIDogJywgcm91bmQoZXN0aW1hdGUqMTAwLDIpLCclJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPGJyIC8+ICUgZXN0aW1hdGVkIDogJywgcm91bmQobnVsbC52YWx1ZSoxMDAsMiksJyUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICc8YnIgLz4gU2FsaWVuY2UgOiAnLCByb3VuZChzYWxpZW5jZSwyKSwgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICc8YnIgLz4gcC52YWx1ZSA6ICcsIHJvdW5kKHAudmFsdWUsNCkpLAogICAgICAgICAgICAgICB0eXBlID0gImJhciIpICAlPiUKICAgIGxheW91dCh0aXRsZSA9IHRpdGxlLAogICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICIlIG5ld3MiKSwKICAgICAgICAgICBiYXJtb2RlID0gJ3N0YWNrJykKICAKICBvdXRwdXQ8LWxpc3QoInRhYmxlIiA9IHRhYiwgInBsb3RseSIgPXApCiAgCiAgcmV0dXJuKG91dHB1dCkKICAKfQpgYGAKCiMjIyBBcHBsaWNhdG9uIG7CsDEgOiBjb3ZpZCB0b3BpYwoKCmBgYHtyfQp3aG8ud2hhdChoY195ZWFyKQpgYGAKCgoKIyMjIEFwcGxpY2F0aW9uIG7CsDIgOiBzdGF0ZSBzdWJ0b3BpYwoKYGBge3J9CnJlcyA8LWhjX3llYXIgJT4lIGZpbHRlcihzdGF0ZXMgIT0gIl9ub18iKSAlPiUKd2hvLndoYXQod2hhdCA9ICJzdGF0ZXMiLAogICAgIHN1YnRvcCA9IlJVUyIsCiAgICAgdGl0bGUgPSAiU2hhcmUgb2YgUnVzc2lhIGluIGludGVybmF0aW9uYWwgbmV3cyIsCiAgICAgdGVzdD1UUlVFKQpyZXMkdGFibGUKcmVzJHBsb3RseQpgYGAKCiMjIyBBcHBsaWNhdGlvbiBuwrAzIDogbWFjcm9yZWdpb24gc3VidG9waWMKCmBgYHtyfQpyZXMgPC1oY195ZWFyICU+JSBmaWx0ZXIocmVnaW9ucyAhPSAiX25vXyIpICU+JQp3aG8ud2hhdCh3aGF0ID0gInJlZ2lvbnMiLAogICAgIHN1YnRvcCA9Ik9SX0VVIiwKICAgICB0aXRsZSA9ICJTaGFyZSBvZiBFVSBpbiBtYWNyb3JlZ2lvbmFsIG5ld3MiLAogICAgIHRlc3Q9VFJVRSkKcmVzJHRhYmxlCnJlcyRwbG90bHkKYGBg